import React from 'react';

export type ErrorBoundaryProps = {
  /** 异常兜底组件 */
  fallbackHolder?: React.ReactNode;
  /** 异常回调 */
  onError?: (error: Error, info: string) => void;
  /** 包裹组件 */
  children: React.ReactNode;
};

type ErrorBoundaryState = {
  /** 错误信息 */
  error: Error | null;
};

const initialState: ErrorBoundaryState = {
  error: null,
};

export class ErrorBoundary extends React.Component<
  React.PropsWithChildren<ErrorBoundaryProps>,
  ErrorBoundaryState
> {
  state = initialState;

  constructor(props: ErrorBoundaryProps) {
    super(props);
  }

  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    this.triggerError(error, errorInfo);
  }

  triggerError(error: any, errorInfo: any) {
    this.props.onError?.(error, errorInfo?.componentStack);
    this.setState({
      error: error,
    });
  }

  render() {
    const { fallbackHolder } = this.props;
    const { error } = this.state;

    if (error !== null) {
      if (React.isValidElement(fallbackHolder)) {
        return fallbackHolder;
      }
      return null;
    }
    return this.props.children || null;
  }
}
